package com.jiang.starter.web.merge;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * 为所有请求合并执行器初始化定时任务
 * @see Merge
 * @see MergeExecutor
 */
@Slf4j
@Component
public class MergeInitializer {

    @Autowired
    private ApplicationContext applicationContext;
    @Autowired
    private ThreadPoolTaskScheduler threadPoolTaskScheduler;
    @Autowired
    private Map<MergeExecutor<Object,Object>, BlockingQueue<Task>> executorBlockingQueueMap;

    /**
     * 将所有MergeExecutor添加到定时任务
     */
    @PostConstruct
    public void init() {

        // 获取所有MergeExecutor
        Map<String, MergeExecutor> mergeExecutorMap = applicationContext.getBeansOfType(MergeExecutor.class);
        for (MergeExecutor<Object,Object> mergeExecutor : mergeExecutorMap.values()) {

            // 为每一个MergeExecutor绑定任务队列
            BlockingQueue<Task> taskQueue = new LinkedBlockingQueue<>();
            executorBlockingQueueMap.put(mergeExecutor, taskQueue);

            // 将其和队列添加到定时任务中
            threadPoolTaskScheduler.scheduleAtFixedRate(() -> {

                // 无任务就返回
                log.info("定时任务开始执行");
                if (taskQueue.isEmpty()) {
                    log.info("定时任务执行结束，此时暂无任务");
                    return;
                }
                int N = taskQueue.size();

                // 获取任务
                List<Task> tasks = new ArrayList<>(N);
                for (int i = 0; i < N; i++) {
                    Task task = taskQueue.poll();
                    tasks.add(task);
                }

                // 封装参数
                List<Object> params = new ArrayList<>(N);
                tasks.forEach(task -> {
                    params.add(task.param);
                });

                // 获取结果
                List<Object> results = mergeExecutor.execute(params);

                // 返回结果
                for (int i = 0; i < N; i++) {
                    Task task = tasks.get(i);
                    Object result = results.get(i);
                    task.completableFuture.complete(result);
                }
                log.info("定时任务执行结束，共完成{}个任务", N);
            }, mergeExecutor.period());
        }
    }

}
